bitkeeper revision 1.757 (40422543Wg1i77yDldDqmAGZ6DVnnQ)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Sun, 29 Feb 2004 17:45:39 +0000 (17:45 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Sun, 29 Feb 2004 17:45:39 +0000 (17:45 +0000)
xl_evtchn.c, event_channel.h, event_channel.c, Xc.c, xc.h:
  Cleanups and fixes for event channels.

tools/xc/lib/xc.h
tools/xc/py/Xc.c
xen/common/event_channel.c
xen/include/hypervisor-ifs/event_channel.h
xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c

index 2200177932e9111663b5a04e4f277dd58653a81d..907aa56c302436e35ae04702d69e049cfd4e464a 100644 (file)
@@ -162,7 +162,7 @@ int xc_vbd_probe(int xc_handle,
 #define EVTCHNSTAT_connected    2  /* Channel is connected to remote.     */
 int xc_evtchn_open(int xc_handle,
                    u64 dom1,   /* may be DOMID_SELF */
-                   u64 dom2,
+                   u64 dom2,   /* may be DOMID_SELF */
                    int *port1,
                    int *port2);
 int xc_evtchn_close(int xc_handle,
index fe29da1cde19cdbe276856ce76f10832df88d318..7ee540afc551449dcc9a55b770c0faf0a24ff554 100644 (file)
@@ -772,13 +772,13 @@ static PyObject *pyxc_evtchn_open(PyObject *self,
     XcObject *xc = (XcObject *)self;
     PyObject *dict;
 
-    u64 dom1 = DOMID_SELF, dom2;
+    u64 dom1 = DOMID_SELF, dom2 = DOMID_SELF;
     int port1, port2, ret;
 
-    static char *kwd_list[] = { "dom2", "dom1", NULL };
+    static char *kwd_list[] = { "dom1", "dom2", NULL };
 
-    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "L|L", kwd_list, 
-                                      &dom2, &dom1) )
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|LL", kwd_list, 
+                                      &dom1, &dom2) )
     {
         DPRINTF("could not parse parameter list.");
         return NULL;
@@ -1163,7 +1163,7 @@ static PyMethodDef pyxc_methods[] = {
       METH_VARARGS | METH_KEYWORDS, "\n"
       "Open an event channel between two domains.\n"
       " dom1 [long, SELF]: First domain to be connected.\n"
-      " dom2 [long]:       Second domain to be connected.\n\n"
+      " dom2 [long, SELF]: Second domain to be connected.\n\n"
       "Returns: [dict] dictionary is empty on failure.\n"
       " port1 [int]: Port-id for endpoint at dom1.\n"
       " port2 [int]: Port-id for endpoint at dom2.\n" },
index 5812109ae6e72d54417991b84ceab0302d440857..919e9855cc988c2e5561ac973860281c30b3ee59 100644 (file)
@@ -92,15 +92,10 @@ static long event_channel_open(evtchn_open_t *open)
     if ( !IS_PRIV(current) )
         return -EPERM;
 
-    /* 'dom1' may be DOMID_SELF. 'dom2' cannot be.*/
     if ( dom1 == DOMID_SELF )
         dom1 = current->domain;
     if ( dom2 == DOMID_SELF )
-        return -EINVAL;
-
-    /* Event channel must connect distinct domains. */
-    if ( dom1 == dom2 )
-        return -EINVAL;
+        dom2 = current->domain;
 
     if ( ((p1 = find_domain_by_id(dom1)) == NULL) ||
          ((p2 = find_domain_by_id(dom2)) == NULL) )
@@ -118,7 +113,8 @@ static long event_channel_open(evtchn_open_t *open)
     }
     else
     {
-        spin_lock(&p2->event_channel_lock);
+        if ( p1 != p2 )
+            spin_lock(&p2->event_channel_lock);
         spin_lock(&p1->event_channel_lock);
     }
 
@@ -148,7 +144,8 @@ static long event_channel_open(evtchn_open_t *open)
     
  out:
     spin_unlock(&p1->event_channel_lock);
-    spin_unlock(&p2->event_channel_lock);
+    if ( p1 != p2 )
+        spin_unlock(&p2->event_channel_lock);
     
     put_task_struct(p1);
     put_task_struct(p2);
@@ -191,7 +188,7 @@ static long __event_channel_close(struct task_struct *p1, int port1)
             {
                 spin_lock(&p2->event_channel_lock);
             }
-            else
+            else if ( p1 != p2 )
             {
                 spin_unlock(&p1->event_channel_lock);
                 spin_lock(&p2->event_channel_lock);
@@ -234,7 +231,8 @@ static long __event_channel_close(struct task_struct *p1, int port1)
 
     if ( p2 != NULL )
     {
-        spin_unlock(&p2->event_channel_lock);
+        if ( p1 != p2 )
+            spin_unlock(&p2->event_channel_lock);
         put_task_struct(p2);
     }
     
index 573953d24600e29a8946a1c0df687f6a5514d1e6..159f146b2f10f1e87e474e26e106ffebaa281f4b 100644 (file)
@@ -12,7 +12,7 @@
 /*
  * EVTCHNOP_open: Open a communication channel between <dom1> and <dom2>.
  * NOTES:
- *  1. <dom1> may be specified as DOMID_SELF.
+ *  1. <dom1> and/or <dom2> may be specified as DOMID_SELF.
  *  2. Only a sufficiently-privileged domain may create an event channel.
  *  3. <port1> and <port2> are only supplied if the op succeeds.
  */
index 82af52ec8cc49a44ec9a43e482b2372e9fbaa54d..1bfd377f9a34720f273271971851d41a3b99e247 100644 (file)
@@ -30,6 +30,10 @@ typedef void (*evtchn_receiver_t)(unsigned int);
 /* /dev/xeno/evtchn resides at device number major=10, minor=200 */
 #define EVTCHN_MINOR 200
 
+/* /dev/xeno/evtchn ioctls: */
+/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */
+#define EVTCHN_RESET _IO('E', 1)
+
 /* NB. This must be shared amongst drivers if more things go in /dev/xeno */
 static devfs_handle_t xeno_dev_dir;
 
@@ -37,8 +41,10 @@ static devfs_handle_t xeno_dev_dir;
 static unsigned long evtchn_dev_inuse;
 
 /* Notification ring, accessed via /dev/xeno/evtchn. */
+#define RING_SIZE     2048  /* 2048 16-bit entries */
+#define RING_MASK(_i) ((_i)&(RING_SIZE-1))
 static u16 *ring;
-static unsigned int ring_cons, ring_prod;
+static unsigned int ring_cons, ring_prod, ring_overflow;
 
 /* Processes wait on this queue via /dev/xeno/evtchn when ring is empty. */
 static DECLARE_WAIT_QUEUE_HEAD(evtchn_wait);
@@ -146,11 +152,18 @@ static inline void process_bitmask(u32 *sel,
             }
             else if ( ring != NULL )
             {
-                ring[ring_prod] = (u16)(port | port_subtype);
-                if ( ring_cons == ring_prod++ )
+                if ( (ring_prod - ring_cons) < RING_SIZE )
+                {
+                    ring[RING_MASK(ring_prod)] = (u16)(port | port_subtype);
+                    if ( ring_cons == ring_prod++ )
+                    {
+                        wake_up_interruptible(&evtchn_wait);
+                        kill_fasync(&evtchn_async_queue, SIGIO, POLL_IN);
+                    }
+                }
+                else
                 {
-                    wake_up_interruptible(&evtchn_wait);
-                    kill_fasync(&evtchn_async_queue, SIGIO, POLL_IN);
+                    ring_overflow = 1;
                 }
             }
         }
@@ -178,21 +191,62 @@ static void evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
     spin_unlock_irqrestore(&lock, flags);
 }
 
+static void __evtchn_reset_buffer_ring(void)
+{
+    u32          m;
+    unsigned int i, j;
+
+    /* Initialise the ring with currently outstanding notifications. */
+    ring_cons = ring_prod = ring_overflow = 0;
+
+    for ( i = 0; i < 32; i++ )
+    {
+        m = pend_outstanding[i];
+        while ( (j = ffs(m)) != 0 )
+        {
+            m &= ~(1 << --j);
+            if ( rx_fns[(i * 32) + j] == NULL )
+                ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_NORMAL);
+        }
+
+        m = disc_outstanding[i];
+        while ( (j = ffs(m)) != 0 )
+        {
+            m &= ~(1 << --j);
+            if ( rx_fns[(i * 32) + j] == NULL )
+                ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_DISCONNECT);
+        }
+    }
+}
+
 static ssize_t evtchn_read(struct file *file, char *buf,
                            size_t count, loff_t *ppos)
 {
     int rc;
+    unsigned int c, p, bytes1 = 0, bytes2 = 0;
     DECLARE_WAITQUEUE(wait, current);
 
     add_wait_queue(&evtchn_wait, &wait);
 
+    if ( (count <= 0) || (count > PAGE_SIZE) || ((count&1) != 0) )
+    {
+        rc = -EINVAL;
+        goto out;
+    }
+
     for ( ; ; )
     {
         set_current_state(TASK_INTERRUPTIBLE);
 
-        if ( ring_cons != ring_prod )
+        if ( (c = ring_cons) != (p = ring_prod) )
             break;
 
+        if ( ring_overflow )
+        {
+            rc = -EFBIG;
+            goto out;
+        }
+
         if ( file->f_flags & O_NONBLOCK )
         {
             rc = -EAGAIN;
@@ -208,11 +262,35 @@ static ssize_t evtchn_read(struct file *file, char *buf,
         schedule();
     }
 
-    rc = -EINVAL;
-    if ( count >= sizeof(ring_prod) )
-        rc = put_user(ring_prod, (unsigned int *)buf);
-    if ( rc == 0 )
-        rc = sizeof(ring_prod);
+    rc = -EFAULT;
+
+    /* Byte length of first chunk. May be truncated by ring wrap. */
+    if ( ((c ^ p) & RING_SIZE) != 0 )
+        bytes1 = (RING_SIZE - RING_MASK(c)) * sizeof(u16);
+    else
+        bytes1 = (p - c) * sizeof(u16);
+
+    /* Further truncate chunk length according to caller's maximum count. */
+    if ( bytes1 > count )
+        bytes1 = count;
+
+    /* Copy the first chunk. */
+    if ( copy_to_user(buf, &ring[c], bytes1) != 0 )
+        goto out;
+
+    /* More bytes to copy? */
+    if ( count > bytes1 )
+    {
+        bytes2 = RING_MASK(p) * sizeof(u16);
+        if ( bytes2 > count )
+            bytes2 = count;
+        if ( (bytes2 != 0) && copy_to_user(&buf[bytes1], &ring[0], bytes2) )
+            goto out;
+    }
+
+    ring_cons = (bytes1 + bytes2) / sizeof(u16);
+
+    rc = bytes1 + bytes2;
 
  out:
     __set_current_state(TASK_RUNNING);
@@ -223,47 +301,58 @@ static ssize_t evtchn_read(struct file *file, char *buf,
 static ssize_t evtchn_write(struct file *file, const char *buf,
                             size_t count, loff_t *ppos)
 {
-    int          rc = -EINVAL;
-    unsigned int new_cons = 0;
+    int  rc, i;
+    u16 *kbuf = (u16 *)get_free_page(GFP_KERNEL);
 
-    if ( count >= sizeof(new_cons) )
-        rc = get_user(new_cons, (unsigned int *)buf);
+    if ( kbuf == NULL )
+        return -ENOMEM;
 
-    if ( rc != 0 )
-        return rc;
+    if ( (count <= 0) || (count > PAGE_SIZE) || ((count&1) != 0) )
+    {
+        rc = -EINVAL;
+        goto out;
+    }
+
+    if ( copy_from_user(kbuf, buf, count) != 0 )
+    {
+        rc = -EFAULT;
+        goto out;
+    }
 
-    rc = sizeof(new_cons);
+    for ( i = 0; i < (count/2); i++ )
+        evtchn_clear_port(kbuf[i]);
 
-    while ( ring_cons != new_cons )
-        evtchn_clear_port(ring[ring_cons++]);
+    rc = count;
 
+ out:
+    free_page((unsigned long)kbuf);
     return rc;
 }
 
+static int evtchn_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+    if ( cmd != EVTCHN_RESET )
+        return -EINVAL;
+
+    spin_lock_irq(&lock);
+    __evtchn_reset_buffer_ring();
+    spin_unlock_irq(&lock);   
+
+    return 0;
+}
+
 static unsigned int evtchn_poll(struct file *file, poll_table *wait)
 {
     unsigned int mask = POLLOUT | POLLWRNORM;
     poll_wait(file, &evtchn_wait, wait);
     if ( ring_cons != ring_prod )
         mask |= POLLIN | POLLRDNORM;
+    if ( ring_overflow )
+        mask = POLLERR;
     return mask;
 }
 
-static int evtchn_mmap(struct file *file, struct vm_area_struct *vma)
-{
-    /* Caller must map a single page of memory from 'file offset' zero. */
-    if ( (vma->vm_pgoff != 0) || ((vma->vm_end - vma->vm_start) != PAGE_SIZE) )
-        return -EINVAL;
-
-    /* Not a pageable area. */
-    vma->vm_flags |= VM_RESERVED;
-
-    if ( remap_page_range(vma->vm_start, 0, PAGE_SIZE, vma->vm_page_prot) )
-        return -EAGAIN;
-
-    return 0;
-}
-
 static int evtchn_fasync(int fd, struct file *filp, int on)
 {
     return fasync_helper(fd, filp, on, &evtchn_async_queue);
@@ -271,9 +360,7 @@ static int evtchn_fasync(int fd, struct file *filp, int on)
 
 static int evtchn_open(struct inode *inode, struct file *filp)
 {
-    u16         *_ring;
-    u32          m;
-    unsigned int i, j;
+    u16 *_ring;
 
     if ( test_and_set_bit(0, &evtchn_dev_inuse) )
         return -EBUSY;
@@ -283,30 +370,8 @@ static int evtchn_open(struct inode *inode, struct file *filp)
         return -ENOMEM;
 
     spin_lock_irq(&lock);
-
     ring = _ring;
-
-    /* Initialise the ring with currently outstanding notifications. */
-    ring_cons = ring_prod = 0;
-    for ( i = 0; i < 32; i++ )
-    {
-        m = pend_outstanding[i];
-        while ( (j = ffs(m)) != 0 )
-        {
-            m &= ~(1 << --j);
-            if ( rx_fns[(i * 32) + j] == NULL )
-                ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_NORMAL);
-        }
-
-        m = disc_outstanding[i];
-        while ( (j = ffs(m)) != 0 )
-        {
-            m &= ~(1 << --j);
-            if ( rx_fns[(i * 32) + j] == NULL )
-                ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_DISCONNECT);
-        }
-    }
-
+    __evtchn_reset_buffer_ring();
     spin_unlock_irq(&lock);
 
     MOD_INC_USE_COUNT;
@@ -335,8 +400,8 @@ static struct file_operations evtchn_fops = {
     owner:    THIS_MODULE,
     read:     evtchn_read,
     write:    evtchn_write,
+    ioctl:    evtchn_ioctl,
     poll:     evtchn_poll,
-    mmap:     evtchn_mmap,
     fasync:   evtchn_fasync,
     open:     evtchn_open,
     release:  evtchn_release